from .common import *
from JDjango.api import model_type_data
from JDjango.api import retools
from JDjango.api import djangotools
from JDjango.api._tools import *
from copy import deepcopy
from ..MessageDialog import RichMsgDialog

class ModelMetaDialog(wx.Dialog):
    def __init__(self, parent, app_name: str, model_name: str, model_path: str):
        wx.Dialog.__init__(self, parent, id = wx.ID_ANY, title = f'【{model_name}】模型 Meta 设置', size=(555, 600), style=wx.DEFAULT_DIALOG_STYLE|wx.MAXIMIZE_BOX|wx.MINIMIZE_BOX|wx.RESIZE_BORDER)
        self.app_name: str = app_name
        self.model_name: str = model_name
        self.model_path: str = model_path
        self._init_data()
        self._init_UI()
        self._init_listener()

    def _init_data(self):
        '''初始化数据'''
        self.ctrs_enabled = {
            
        }
        # self.meta_options 用于存放最初的选项，一：用于初始化属性面板的值；二：用于比对生成修改代码
        self.meta_options: Dict[str, Any] = djangotools.get_meta_exist_options(self.model_path, self.model_name) # 模型中的Meta参数选项字典集
        self.options: Dict[str, Any] = None # meta_options.json 的数据集
        self.filed_key_names = {} # 存储如 {'max_length': '[最大长度]-[max_length]'},.方便属性面板的取值

        '''
            最初的数据存留【深拷贝】：用于最后的关键字参数和位置参数的生成【比对用】。
        '''
        self.deepcopy_attr_datas: Dict[str, Any] = None # 初始化时的属性面板值

        '''
            模板填充值【用于在json数据中使用模板替换功能】
        '''
        self._init_template_values()

    def _init_listener(self):
        '''注册监听'''
        self.Bind(wxpg.EVT_PG_SELECTED, self.onPgSelected, self.pgPanel)
        self.Bind(wx.EVT_BUTTON, self.onBtnModify, self.btn_modify)

    def _init_template_values(self):
        '''初始化模板填充值，选项暂定'''


    def _init_UI(self):
        """初始化界面布局"""
        self.panel = wx.Panel(self)
        self.panelSizer = wx.BoxSizer(wx.VERTICAL)
        self.panel.SetSizer(self.panelSizer)

        info = f"正在为【{self.app_name}】应用程序下的【{self.model_name}】模型修改【Meta】选项。"
        static_info = wx.StaticText(self.panel, -1, info)
        static_info.SetForegroundColour(wx.RED)
        self.panelSizer.Add(static_info, 0, wx.EXPAND | wx.ALL, 5)

        '''
            工具栏
        '''
        self.toolsPanel = wx.Panel(self.panel)
        self.toolsPanelSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.toolsPanel.SetSizer(self.toolsPanelSizer)
        self.panelSizer.Add(self.toolsPanel, 0, wx.EXPAND | wx.ALL, 5)

        self.toolsPanelSizer.Add((5, 5), 1, wx.EXPAND | wx.ALL, 5)

        self.btn_modify = buttons.GenButton(self.toolsPanel, -1, '修改')
        self.btn_modify.SetBackgroundColour(CON_COLOR_MAIN)
        self.btn_modify.SetForegroundColour(CON_COLOR_PURE_WHITE)
        self.toolsPanelSizer.Add(self.btn_modify, 0, wx.EXPAND | wx.ALL, 5)

        self.toolsPanelSizer.Add((5, 5), 1, wx.EXPAND | wx.ALL, 5)

        '''
            属性面板
        '''
        self.pgPanel = wxpg.PropertyGridManager(
            self.panel,
            style = wxpg.PG_BOLD_MODIFIED # 修改后的值自动加粗
                | wxpg.PG_SPLITTER_AUTO_CENTER # 自动居中分离
                | wxpg.PG_NO_INTERNAL_BORDER # 无边框
                | wxpg.PG_TOOLBAR # 带工具条（用于切换不同的配置页）
                | wxpg.PG_DESCRIPTION # 带描述信息
                | wxpg.PGMAN_DEFAULT_STYLE # 启用默认风格
        )
        self.panelSizer.Add(self.pgPanel, 1, wx.EXPAND | wx.ALL, 5)
        self.pgPanel.ExtraStyle |= wxpg.PG_EX_HELP_AS_TOOLTIPS # 扩展工具栏帮助提示信息属性
        self.pgPanel.SetDescBoxHeight(89)

        self._init_pages()

    def _init_pages(self):
        '''初始化页面信息'''
        page = self.pgPanel.AddPage('基本')
        page.Append(wxpg.PropertyCategory(f'基本选项'))
        self.options: Dict[str, Any] = model_type_data.read_meta_options()
        for k, option in self.options.items():
            if not option.get("deprecated"):
                prop_type = option.get("type")
                prop_name = f'[{option["name"]}]-[{k}]'
                self.filed_key_names[k] = prop_name

                default = option["default"]
                '''
                    默认值根据实际刷新
                '''
                if k in self.meta_options:
                    default = self.meta_options[k]

                if "StringProperty" == prop_type:
                    # 一次赋值的可以在这里进行模板替换
                    temp = retools.patt_template_replace(
                        retools.PATT_REPLACE
                        , default
                        , app_name = self.app_name.split('.')[-1].lower()
                        , model_name = self.model_name
                        , model_name_space = self.model_name.replace("_", " ")
                    ) # 通用的赋值模板
                    page.Append(wxpg.StringProperty(prop_name, value=temp))
                elif "EnumProperty" == prop_type:
                    page.Append(wxpg.EnumProperty(prop_name, prop_name, ['',]+default, list(range(len(default)+1)), 0))
                elif "ArrayStringProperty" == prop_type:
                    page.Append(wxpg.ArrayStringProperty(prop_name, value=default))
                elif "BoolProperty" == prop_type:
                    page.Append(wxpg.BoolProperty(prop_name, value=default))
                elif "IntProperty" == prop_type:
                    page.Append(wxpg.IntProperty(prop_name, value=default))
                elif "FloatProperty" == prop_type:
                    page.Append(wxpg.FloatProperty(prop_name, value=default))

        '''
            此处的比对数据已经经过初始化和实际值初始化两个步骤，足够保证比对数据时的正确性
        '''
        self.deepcopy_attr_datas = deepcopy(self.pgPanel.GetPropertyValues(inc_attributes=True)) # 深拷贝，数据预存

    def _get_key_from_name(self, name: str) -> str:
        """从选项名获取键值【规则为本工具自主约定的格式】"""
        try:
            return name.split('-')[1].strip('[]')
        except:
            return ''
            
    def onPgSelected(self, evt: wxpg.PropertyGridEvent):
        '''属性被选中'''
        if self.options is not None:
            name = evt.GetPropertyName()
            try:
                tips = "".join(self.options[self._get_key_from_name(name)]["tips"])
            except:
                try:
                    tips = "".join(self.field_type["extra_options"][self._get_key_from_name(name)]["tips"])
                except:
                    tips = ""
            self.pgPanel.SetDescription(name, tips)

    def onBtnModify(self, evt):
        '''保存字段
        
            保存前适当提醒【原则上，不会对用户的逻辑做任何控制】

            算法原理：（暂时只处理只有一行的参数情况，拆行不作处理）
                先定位到 Meta 区域
                然后定位到唯一的参数行
                将值替换后，整体替换这一行
                最后用新的Meta数据区域，替换原先的Meta数据区域
        '''
        
        if RichMsgDialog.showYesNoMsgDialog(self, f"正在修改【{self.app_name}】应用程序下的【{self.model_name}】模型的【Meta】选项", '提示'):
            
            compare_args = self._compare_Meta_args() # 值变动的 Meta 参数
            # 抠出Mate区域
            meta_content: str = djangotools.cut_model_Meta_content_from_file(self.model_path, self.model_name)
            sp_meta_content: List[str] = meta_content.split('\n')
            for i, line in enumerate(sp_meta_content):
                sp_line = line.split('=')
                k = sp_line[0].strip()
                if k in compare_args: # 存在则修改
                    value = compare_args[k]["new"]
                    if self.options[k]["quot"]:
                        value = self._add_quot_around_string(value)
                    sp_meta_content[i] = line.replace(('='.join(sp_line[1:])).strip(), value)
                    '''
                        用完之后就删，为后面新增留功能
                    '''
                    del compare_args[k]
            '''
                原则上，先修改，后新增
            '''
            # 修改
            write_file(self.model_path, read_file(self.model_path).replace(meta_content, '\n'.join(sp_meta_content)))

            # 新增一组参数选项【传入列表参数】
            if len(compare_args) > 0:
                field_codes = [] # self.options
                for _k, _v in compare_args.items():
                    value = _v["new"]
                    if self.options[_k]["quot"]:
                        value = self._add_quot_around_string(value)
                    field_codes.append(f"{_k} = {value}")
                djangotools.insert_option_into_meta(self.model_path, self.model_name, field_codes)
            
            RichMsgDialog.showOkMsgDialog(self, "修改 Meta 成功！", "成功")

    def _compare_Meta_args(self)->Dict[str, Dict[str, Any]]:
        '''比对Meta的参数数据'''
        self.deepcopy_attr_datas # 备份的比对数据
        this_meta_args = self.pgPanel.GetPropertyValues(inc_attributes=True) # 当前的界面参数集
        compare_args: Dict[str, Dict[str, Any]] = {}
        '''
            compare_args数据包的结构定为：
                {
                    "db_table": {
                        "old": "old_name",
                        "new": "new_name"
                    }
                    
                }
            以备份数据为标准，比对当前界面的数据
        '''
        for bak_k, bak_v in self.deepcopy_attr_datas.items():
            if this_meta_args[bak_k] != bak_v: # 修改过【如果是数组，位置修改也是修改】
                bak_k_k = self._get_key_from_name(bak_k)
                compare_args[bak_k_k] = {}
                compare_args[bak_k_k]["old"] = bak_v
                compare_args[bak_k_k]["new"] = this_meta_args[bak_k]
        
        return compare_args

    def _add_quot_around_string(self, string, quot_str: str="'"):
        '''为一个字符串两侧添加引号（用引号括起来）
        
            默认为单引号
        '''
        return f"{quot_str}{string}{quot_str}"
